package com.youzi.tunnel.client.handlers;

import com.youzi.tunnel.client.config.ClientProperties;
import com.youzi.tunnel.common.protocol.Constants;
import com.youzi.tunnel.common.protocol.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * 隧道客户端连接端口一方处理
 */
@Slf4j
public class TunnelClientChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private static final boolean isDebugger = ClientProperties.getInstance().isDebugger();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) {
        //收到来自连接的信息
        Channel channel = ctx.channel();
        InetSocketAddress address = (InetSocketAddress) (ctx.channel().remoteAddress());

        //监听端口获取到信息, 尝试获取目标Channel, 为空则请求开启链路
        Channel toChannel = channel.attr(Constants.TOWARD_CHANNEL).get();

        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);

        if (isDebugger) {
            log.info("收到主机[{}:{}]请求消息, 将转发到服务器, 数据长度: {} [byte]", address.getHostString(), address.getPort(), bytes.length);
        }
        int i = 10;
        while (toChannel == null) {//认证后有的服务会立刻返回数据并且等待连接，如mysql
            i--;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            toChannel = channel.attr(Constants.TOWARD_CHANNEL).get();
            if (i < 0) {
                break;
            }

        }
        if (toChannel != null) {
            //转发信息
            Message message = new Message();
            message.setType(Message.TYPE.RELAY);
            message.setData(bytes);

            toChannel.writeAndFlush(message);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Channel channel = ctx.channel();
        InetSocketAddress address = (InetSocketAddress) (ctx.channel().remoteAddress());

        log.error("连接隧道断开连接[{}:{}, channelId={}], message: {}", address.getHostString(), address.getPort(), channel.id(), cause.getMessage());

        Channel towardChannel = channel.attr(Constants.TOWARD_CHANNEL).get();

        Message message = new Message();
        message.setType(Message.TYPE.CLOSE_CONNECT);

        towardChannel.writeAndFlush(message);
        //下发关闭对向连接链路
        towardChannel.writeAndFlush(message);
        towardChannel.close().sync();
        channel.close().sync();
        super.exceptionCaught(ctx, cause);
    }
}
